/**
 * Created by sun on 2015/3/12.
 */
package com.jbm.jbmsupplier.util;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.apache.mina.core.future.ReadFuture;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.transport.socket.SocketSessionConfig;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.*;
import org.apache.mina.filter.executor.*;
import org.apache.mina.transport.socket.nio.NioSocketConnector;

import java.io.RandomAccessFile;

import org.slf4j.*;

public class Interface
{
    public Interface ( )
    {
        this.BUFFER_LEN = 65536;
        this.pver = 0;
        this.sver = 3;
        this.build = 12;
    }

    private NioSocketConnector connector;
    private ConnectFuture cf;
    private IoSession ios;
    private String ip;
    private int port;
    private int timeout;
    protected int BUFFER_LEN;

    public int pver;
    public int sver;
    public int build;

    public String Connect ( String ip, int port, int timeout )
    {
        this.ip = ip;
        this.port = port;
        this.timeout = timeout;
        this.connector = new NioSocketConnector();
        this.connector.setConnectTimeoutMillis(timeout);
        this.connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new OHCodeFactory("UTF-8")));
        SocketSessionConfig cfg = this.connector.getSessionConfig();
        cfg.setUseReadOperation(true);
        this.cf = this.connector.connect ( new InetSocketAddress(ip,port) );
        this.cf.awaitUninterruptibly ( );

        this.ios = this.cf.getSession();

        return "OK";
    }

    public String ConfirmVer ( )
    {
        try {
            this.ios.write(new IVersion(pver,sver,build)).awaitUninterruptibly();
            ReadFuture rf = this.ios.read();
            if (rf.await(this.timeout, TimeUnit.MILLISECONDS)) {
                String status = (String) rf.getMessage();
                return status;
            }else
                return "FAILED";
        }catch (Exception e){
            return "FAILED";
        }
    }

    public String Login ( String name, String pass)
    {
        try {
            this.ios.write(new ILogin(name, pass)).awaitUninterruptibly();
            ReadFuture rf = this.ios.read();
            if (rf.await(this.timeout, TimeUnit.MILLISECONDS)) {
                String status = (String) rf.getMessage();
                return status;
            }else
                return "FAILED";
        }catch (Exception e){
            return "FAILED";
        }
    }

    public JobList GetJobList ( int start, int count)
    {
        try {
            this.ios.write(new IGetJobList(start, count)).awaitUninterruptibly();
            ReadFuture rf = this.ios.read();
            if (rf.await(this.timeout, TimeUnit.MILLISECONDS)) {
                JobList jl = (JobList) rf.getMessage();
                return jl;
            }else
                return null;
        }catch (Exception e){
            return null;
        }
    }

    public Job LoadJob ( int jobid )
    {
        try {
            this.ios.write(new ILoadJob(jobid)).awaitUninterruptibly();
            ReadFuture rf = this.ios.read();
            if (rf.await(this.timeout, TimeUnit.MILLISECONDS)) {
                Job job = (Job) rf.getMessage();
                return job;
            }else
                return null;
        }catch (Exception e){
            return null;
        }
    }

    public String BreakJob ( int jobid )
    {
        try {
            this.ios.write(new IBreakJob(jobid)).awaitUninterruptibly();
            ReadFuture rf = this.ios.read();
            if (rf.await(this.timeout, TimeUnit.MILLISECONDS)) {
                String status = (String) rf.getMessage();
                return status;
            }else
                return "FAILED";
        }catch (Exception e){
            return "FAILED";
        }
    }

    public String SubmitJob ( int jobid )
    {
        try {
            this.ios.write(new ISubmitJob(jobid)).awaitUninterruptibly();
            ReadFuture rf = this.ios.read();
            if (rf.await(this.timeout, TimeUnit.MILLISECONDS)) {
                String status = (String) rf.getMessage();
                return status;
            }else
                return "FAILED";
        }catch (Exception e){
            return "FAILED";
        }
    }

    public String ConfirmJob ( int jobid )
    {
        try {
            this.ios.write(new IConfirmJob(jobid)).awaitUninterruptibly();
            ReadFuture rf = this.ios.read();
            if (rf.await(this.timeout, TimeUnit.MILLISECONDS)) {
                String status = (String) rf.getMessage();
                return status;
            }else
                return "FAILED";
        }catch (Exception e){
            return "FAILED";
        }
    }

    public Media UploadMedia ( int jobid, Media media )
    {
        try {
            IUploadMedia ium = new IUploadMedia( jobid, media );
            ium.buffer = new byte[BUFFER_LEN];
            if ( !media.mtype.equals("text") )
            {
                Media rtn;

                if ( media.mid == 0 && media.offset > 0 )
                {
                    media.offset = -1;
                    return media;
                }
                RandomAccessFile raf = new RandomAccessFile(media.filepath,"r");
                media.filepath = "";
                raf.seek(media.offset);

                int len;
                do
                {
                    len = raf.read(ium.buffer,0,BUFFER_LEN);

                    ium.bufferlen = len==-1?0:len;
                    this.ios.write(ium).awaitUninterruptibly();
                    ReadFuture rf = this.ios.read();
                    if (rf.await(this.timeout, TimeUnit.MILLISECONDS)) {
                        rtn = (Media) rf.getMessage();

                        if ( rtn.offset != -1 ) {
                            ium.media.offset = rtn.offset;
                            ium.media.mid = rtn.mid;
                            ium.media.filepath = rtn.filepath;
                        }else
                            return rtn;
                    } else {
                        media.offset = -1;
                        return media;
                    }
                }while ( len != -1 );

                raf.close();

                return rtn;
            }else {
                this.ios.write(new IUploadMedia(jobid, media)).awaitUninterruptibly();
                ReadFuture rf = this.ios.read();
                if (rf.await(this.timeout, TimeUnit.MILLISECONDS)) {
                    Media rtn = (Media) rf.getMessage();
                    return rtn;
                } else {
                    media.offset = -1;
                    return media;
                }
            }
        }catch (Exception e){
            media.offset = -1;
            return media;
        }
    }

    public Media DownLoadMedia ( Media media )
    {
        try {
            IDownloadMedia idm = new IDownloadMedia( media );
            idm.buffer = new byte[BUFFER_LEN];
            if ( !media.mtype.equals("text") )
            {
                Media rtn;

                if ( media.mid <= 0 )
                {
                    media.offset = -1;
                    return media;
                }
                RandomAccessFile raf = new RandomAccessFile(media.filepath,"rw");
                media.filepath = "";
                raf.seek(media.offset);

                int len;
                do
                {
                    len = raf.read(idm.buffer,0,BUFFER_LEN);

                    idm.bufferlen = len==-1?0:len;
                    this.ios.write(idm).awaitUninterruptibly();
                    ReadFuture rf = this.ios.read();
                    if (rf.await(this.timeout, TimeUnit.MILLISECONDS)) {
                        rtn = (Media) rf.getMessage();

                        if ( rtn.offset != -1 ) {
                            idm.media.offset = rtn.offset;
                            idm.media.mid = rtn.mid;
                            idm.media.filepath = rtn.filepath;
                        }else
                            return rtn;
                    } else {
                        media.offset = -1;
                        return media;
                    }
                }while ( len != -1 );

                raf.close();

                return rtn;
            }else {
                this.ios.write(new IDownloadMedia(media)).awaitUninterruptibly();
                ReadFuture rf = this.ios.read();
                if (rf.await(this.timeout, TimeUnit.MILLISECONDS)) {
                    Media rtn = (Media) rf.getMessage();
                    return rtn;
                } else {
                    media.offset = -1;
                    return media;
                }
            }
        }catch (Exception e){
            media.offset = -1;
            return media;
        }
    }
}
